#include <map>
#include <set>
#include <functional>
#include <cstdint>
#include <ctime>
#include <stdexcept>
struct stUserinfo;

// 时间戳包装类：存储数据和过期时间戳
template<typename T>
struct TimeStamped {
    T data;               // 存储的数据
    std::int64_t timestamp; // 过期时间戳（秒级）

    TimeStamped(const T& val, std::int64_t time) : data(val), timestamp(time) {}
    TimeStamped(T&& val, std::int64_t time) : data(std::move(val)), timestamp(time) {}

    bool expired(std::int64_t now) const {
        return timestamp <= now;
    }

    // 延长过期时间
    void extend(std::int64_t new_expire_time) {
        timestamp = new_expire_time;
    }
};

// 比较器：按时间戳升序排序（用于 set 中快速找到最早过期的元素）
template<typename T>
struct TimeStampComparator {
    bool operator()(const TimeStamped<T>& a, const TimeStamped<T>& b) const {
        // 先按时间戳排序，时间戳相同则按数据排序（避免 set 中元素重复）
        if (a.timestamp != b.timestamp) {
            return a.timestamp < b.timestamp;
        }
        return a.data < b.data;
    }
};

// 用户过期管理器：管理 stUserinfo* 的生命周期，自动清理过期指针
class UserExpireMgr {
private:
    // 类型别名：简化代码
    using Key = std::uint64_t;                  // 键类型（用户 ID）
    using Value = stUserinfo*;                  // 值类型（用户指针）
    using KeyStamp = TimeStamped<Key>;     // 键+过期时间戳（用于 set 排序）
    using Data = TimeStamped<Value>;       // 值+过期时间戳（用于 map 存储）
    using DataMap = std::map<Key, Data>;   // 存储键值对：用户 ID -> (用户指针+过期时间)
    using TimeSet = std::set<KeyStamp, TimeStampComparator<Key>>; // 按过期时间排序的键集合

public:
    // 构造函数：指定默认过期时间（秒），默认 1h
    explicit UserExpireMgr(int default_expire = 60 * 60) 
        : m_defaultExpire(default_expire) {
        if (default_expire <= 0) {
            throw std::invalid_argument("默认过期时间必须为正数");
        }
    }

    // 获取用户指针：存在则自动续期，不存在/过期返回 nullptr
    Value get(const Key key) {
        auto it = m_datas.find(key);
        if (it == m_datas.end()) {
            return nullptr; // 不存在
        }
        // 自动续期
        renew_key(key, it);
        return it->second.data; // 返回用户指针
    }

    // 添加用户指针：若已存在则覆盖，自动设置过期时间
    void insert(const Key key, Value pData) {
        if (pData == nullptr) {
            throw std::invalid_argument("插入的用户指针不能为 nullptr");
        }

        auto now = current_time();
        remove(key); // 先移除旧记录（若存在）

        // 构造新数据：用户指针 + 过期时间（当前时间 + 默认过期时间）
        //Data new_data{pData, now + m_defaultExpire};
        m_datas.emplace(key, TimeStamped<Value>(pData, now + m_defaultExpire));

        // 将键+过期时间插入 set（用于排序和清理）
        m_setkeyTimeStamp.insert(KeyStamp(key, now + m_defaultExpire));

        // 若插入后是第一个元素，触发开始回调
        if (m_datas.size() == 1) {
            invoke_begin_callback();
        }
    }

    // 手动移除用户指针
    void remove(const Key key) {
        auto it = m_datas.find(key);
        if (it == m_datas.end()) {
            return; // 不存在，直接返回
        }

        // 从 set 中移除对应的键+时间戳
        m_setkeyTimeStamp.erase(KeyStamp(key, it->second.timestamp));
        // 从 map 中移除键值对
        m_datas.erase(it);

        // 若为空，触发结束回调
        if (m_datas.empty()) {
            invoke_end_callback();
        }
    }

    // 清理所有用户指针
    void clear() {
        m_datas.clear();
        m_setkeyTimeStamp.clear();
        if (!m_datas.empty()) { // 双重检查（理论上不会触发）
            m_datas.clear();
            m_setkeyTimeStamp.clear();
        }
        invoke_end_callback(); // 无论是否为空，都触发结束回调
    }

    // 定期清理过期用户指针：调用此函数执行清理（建议定时任务触发）
    void purge_expired() {
        if (m_setkeyTimeStamp.empty()) {
            return;
        }

        auto now = current_time();
        // 遍历 set 中所有过期的元素（set 按时间戳升序，找到第一个未过期的则停止）
        for (auto it = m_setkeyTimeStamp.begin(); it != m_setkeyTimeStamp.end(); ) {
            if (it->expired(now)) {
                // 从 map 中移除对应的键值对
                auto iter = m_datas.find(it->data);
                if (iter != m_datas.end())
                {
                    delete iter->second.data;
                    iter->second.data = nullptr;
                    m_datas.erase(iter);
                }
                it = m_setkeyTimeStamp.erase(it); // 从 set 中移除并移动迭代器
            } else {
                break; // 未过期元素之后的都未过期，直接退出
            }
        }

        // 若清理后为空，触发结束回调
        if (m_datas.empty()) {
            invoke_end_callback();
        }
    }

    // 设置回调：第一个元素插入时触发
    void set_begin_callback(std::function<void()> cb) {
        m_beginCb = std::move(cb);
    }

    // 设置回调：最后一个元素移除时触发
    void set_end_callback(std::function<void()> cb) {
        m_endCb = std::move(cb);
    }

    // 获取当前存储的用户数量
    size_t size() const {
        return m_datas.size();
    }

    // 判断是否为空
    bool empty() const {
        return m_datas.empty();
    }

private:
    // 获取当前时间戳（秒级，基于系统时间）
    std::int64_t current_time() const {
        return static_cast<std::int64_t>(time(nullptr));
    }

    // 为指定用户续期：更新过期时间并同步到 set
    void renew_key(const Key key, typename DataMap::iterator data_it) {
        auto now = current_time();
        auto old_timestamp = data_it->second.timestamp;

        // 更新 map 中的过期时间（当前时间 + 默认过期时间）
        data_it->second.extend(now + m_defaultExpire);
        auto new_timestamp = data_it->second.timestamp;

        // 同步更新 set 中的时间戳：先删旧的，再插新的
        m_setkeyTimeStamp.erase(KeyStamp(key, old_timestamp));
        m_setkeyTimeStamp.insert(KeyStamp(key, new_timestamp));
    }

    // 触发开始回调（确保只在第一次插入时调用）
    void invoke_begin_callback() {
        if (m_beginCb) {
            try {
                m_beginCb(); // 调用用户设置的回调
            } catch (...) {
                // 捕获所有异常，避免回调崩溃影响管理器
            }
        }
    }

    // 触发结束回调（确保只在最后一个元素移除时调用）
    void invoke_end_callback() {
        if (m_endCb) {
            try {
                m_endCb(); // 调用用户设置的回调
            } catch (...) {
                // 捕获所有异常
            }
        }
    }

private:
    DataMap m_datas;              // 核心存储：用户 ID -> (用户指针+过期时间)
    TimeSet m_setkeyTimeStamp;    // 排序集合：按过期时间存储用户 ID，用于快速清理
    int m_defaultExpire;          // 默认过期时间（秒）
    std::function<void()> m_beginCb; // 第一个元素插入时的回调（如启动定时任务）
    std::function<void()> m_endCb;   // 最后一个元素移除时的回调（如停止定时任务）
};